﻿#include "xd_room.hpp"
#include "meet.hpp"
#include "sqlite_conn.hpp"
#include "serv_manage.hpp"

#include "utils/utils_string.hpp"
#include "ws_server.hpp"
#include "wlog.hpp"
#include "serv_manage.hpp"
#include "utils/time.hpp"
#include "meet_room.hpp"



namespace bz {
	xd_room::xd_room(asio::io_context& io, meet_room* room,meet* me, xd_client* xd, int meet_num, terminal* root_ter,bool is_main, bool auto_invite) :
		AsioExecutor(io),
		meet_(me),
		xd_api_(xd),
		is_ready_(false),
		meet_room_(room),
		is_main_(is_main),
		meet_num_(meet_num),
		root_ter_(root_ter),
		shut_down_(false),
		link_status_(true),
		auto_invite_(auto_invite)
	{

	
		parent_room_ter_ = nullptr;

	}

	xd_room::~xd_room()
	{
		
	}

	
	

	async_simple::coro::Lazy<void> xd_room::init()
	{
		co_return;
	}

	void xd_room::before_del()
	{

	}

	async_simple::coro::Lazy<bool> xd_room::start_meet()
	{
		xd_api_->reg_obs(this);
		auto template_list_res = xd_api_->list_template();
		if (!template_list_res.first.ret) {
			meet_room_->error_msg(template_list_res.first.err_code, utils_string::fromLocal8("模板列表获取失败"));
			co_return false;
		}
		if (!template_list_res.second.count(meet_->meet_name)) {
			xd_api_->addTemplate(meet_->meet_name, to_string(meet_->meet_num), meet_->meet_pwd,meet_->sizes,meet_->fps, meet_->bandwidth * 1024000);
		}
		xd_res ret = xd_api_->start_task(meet_->meet_name);

		if (ret.ret) {
			auto device_list_res = xd_api_->list_device();
			if (!device_list_res.first.ret) {
				meet_room_->error_msg(device_list_res.first.err_code, utils_string::fromLocal8("获取终端列表失败"));
				co_return false;
			}

			for (auto it: *terminal_list_)
			{
				if (device_list_res.second.count(it->name)) {
					ret = xd_api_->add_call(meet_->meet_name, it->name,it->is_main? TerminalRole::e_Monitor: TerminalRole::e_Normal);
					if (!ret.ret) {
						meet_room_->error_msg(ret.err_code, utils_string::fromLocal8("邀请终端失败"));
						
					}
				}
				else {
					ret = xd_api_->add_terminal(it->name, it->ip,it->protocol);
					if (ret.ret) {
						ret = xd_api_->add_call(meet_->meet_name, it->name, it->is_main ? TerminalRole::e_Monitor : TerminalRole::e_Normal);
						if (!ret.ret) {
							meet_room_->error_msg(ret.err_code, utils_string::fromLocal8("邀请终端失败"));
							
						}
					}
					else {
						meet_room_->error_msg(ret.err_code, utils_string::fromLocal8("添加终端失败"));
						
					}
					
				}
			}
		}
		else {
			meet_room_->error_msg(ret.err_code, utils_string::fromLocal8("会议开启失败"));
			co_return false;
		}
		
		co_return true;
		
	}

	async_simple::coro::Lazy<bool> xd_room::end_meet()
	{
		xd_res ret = xd_api_->stop_task(meet_->meet_name);
		if (!ret.ret) {
			//meet_room_->error_msg(ret.err_code);
			co_return ret.ret;
		}
		ret  = xd_api_->del_template(meet_->meet_name);
		if (!ret.ret) {
			//meet_room_->error_msg(ret.err_code);
		}
		co_return ret.ret;;
		
	}

	async_simple::coro::Lazy<bool> xd_room::roll(terminal* ter)
	{
		xd_res ret = xd_api_->set_role(meet_->meet_name, ter->name, e_Speaker);
		if (!ret.ret) {
			meet_room_->error_msg(ret.err_code);
			co_return ret.ret;
		}
		ret = xd_api_->set_chair_see_speaker(meet_->meet_name);
		if (!ret.ret) {
			meet_room_->error_msg(ret.err_code);
			co_return ret.ret;
		}
		ret = xd_api_->set_normal_see_speaker(meet_->meet_name);
		if (!ret.ret) {
			meet_room_->error_msg(ret.err_code);
			co_return ret.ret;
		}
		
		for (auto it : *terminal_list_)
		{
			if (it != ter) {
				it->is_poll = false;
				it->choose = false;
				meet_room_->ws_ter_update(it);
			}
		}
		
		co_return ret.ret;;
	}

	async_simple::coro::Lazy<void> xd_room::cancel_roll()
	{
		for (auto it : *terminal_list_)
		{
			if (it->roll) {
				auto ret = xd_api_->set_role(meet_->meet_name, it->name,  it->is_main ? e_Monitor : e_Normal);
				/*if (!ret.ret) {
					meet_room_->error_msg(ret.err_code);
				}*/
				co_return;
			}
		}
		
	}

	async_simple::coro::Lazy<bool> xd_room::choose(terminal* ter, bool is_poll)
	{
		auto ret = xd_api_->choose(meet_->meet_name, ter->name);
		if (ret.ret) {
			ter->is_poll = false;
			ter->choose = false;
			if (is_poll) {
				ter->is_poll = true;
			}
			else {
				ter->choose = true;
			}
			
			meet_room_->ws_ter_update(ter);

			for (auto &it : *terminal_list_)
			{
				if (it->roll) {
					xd_api_->set_role(meet_->meet_name, it->name,it->is_main? e_Monitor : e_Normal);
				}
				if (it  != ter) {
					it->is_poll = false;
					it->choose = false;
					meet_room_->ws_ter_update(it);
				}

			}
		}
		else {
			meet_room_->error_msg(ret.err_code, utils_string::fromLocal8("选看失败"));
		}
		co_return ret.ret;
	}

	async_simple::coro::Lazy<void> xd_room::cancel_choose(terminal* ter)
	{
		co_return;
	}

	async_simple::coro::Lazy<void> xd_room::invite_device(terminal* ter)
	{
		auto ret = xd_api_->add_call(meet_->meet_name, ter->real_name, ter->is_main ? TerminalRole::e_Monitor : TerminalRole::e_Normal);
		if (!ret.ret) {
			
			
			meet_room_->error_msg(ret.err_code, utils_string::fromLocal8("邀请终端失败"));
		}
		co_return;
	}

	async_simple::coro::Lazy<void> xd_room::set_audio_mute(terminal* ter, bool mute)
	{
		auto ret =  xd_api_->toggle_audio_mute(meet_->meet_name, ter->name, 1, mute);
		if (!ret.ret) {
			meet_room_->error_msg(ret.err_code, utils_string::fromLocal8("混音切换失败"));
		}
		co_return;
	}

	async_simple::coro::Lazy<void> xd_room::hungup_device(terminal* ter)
	{
		auto ret = xd_api_->hangup_call(meet_->meet_name, ter->name);
		if (!ret.ret) {
			meet_room_->error_msg(ret.err_code, utils_string::fromLocal8("挂断终端失败"));
		}
		co_return;
	}

	async_simple::coro::Lazy<void> xd_room::del_terminal(terminal* ter)
	{
		xd_api_->kick_call(meet_->meet_name, ter->name);
		co_return;
	}

	async_simple::coro::Lazy<bool> xd_room::change_layout(int picNum, vector<string>& parti_vec)
	{
		int mixemode = 0;
		switch (picNum)
		{
		case 1:
			mixemode = 0;
			break;
		case 4:
			mixemode = 3;
			break;
		case 9:
			mixemode = 5;
			break;
		case 16:
			mixemode = 8;
			break;
		default:
			break;
		}

		auto ret = xd_api_->multi_choose(meet_->meet_name,mixemode, parti_vec);

		/*if (!ret.ret) {
			meet_room_->error_msg(ret.err_code);
		}*/
		co_return true;
	}

	async_simple::coro::Lazy<void> xd_room::hungup_link()
	{
		co_return;
	}

	async_simple::coro::Lazy<void> xd_room::recall_link()
	{
		co_return;
	}

	async_simple::coro::Lazy<void> xd_room::camera_control(terminal* ter, string cmd, string action)
	{
		int stat = (action == "start") ? 1 : 0;
		auto ret = xd_api_->send_fecc(meet_->meet_name, ter->name, stat, cmd);
		if (!ret.ret) {
			meet_room_->error_msg(ret.err_code);
		}
		co_return;
	}

	async_simple::coro::Lazy<void> xd_room::set_chairman(terminal* ter)
	{

		auto ret = xd_api_->set_role(meet_->meet_name, ter->name, e_Monitor);
		if (ret.ret) {
			ret = xd_api_->toggle_audio_mute(meet_->meet_name, ter->name, 1, false);
			if (!ret.ret) {
				meet_room_->error_msg(ret.err_code);
			}
		}
		else {
			meet_room_->error_msg(ret.err_code);
		}
		co_return;
	}

	async_simple::coro::Lazy<void> xd_room::choose_parent()
	{
		co_return;
	}

	async_simple::coro::Lazy<void> xd_room::hand_all_sound(const bool mute)
	{

		for (auto it : *terminal_list_)
		{
			if(!it->is_main)
				xd_api_->toggle_audio_mute(meet_->meet_name, it->name, 1, mute);
		}
		
		co_return;
	}

	async_simple::coro::Lazy<void> xd_room::set_default()
	{
		co_return;
	}

	void xd_room::remove_ter(terminal* ter)
	{
		name_terminal_map_.erase(ter->name);
	}

	void xd_room::set_terminal_list(std::vector<terminal*>& terminal_list)
	{
		terminal_list_ = &terminal_list;
		name_terminal_map_.clear();
		for (auto &it :  *terminal_list_)
		{
			name_terminal_map_[it->name] = it;
		}
	}

	bool xd_room::in_meeting()
	{
		auto task_set = xd_api_->list_tasks();
		
		if (task_set.first.ret) {
			if (task_set.second.count(meet_->name)) {
				xd_api_->reg_obs(this);
				return true;
			}
		}
		else {
			//meet_room_->error_msg(task_set.first.err_code);
		}
		

		return false;
	}

	bool xd_room::get_meet_info()
	{
		try {
			xmlrpc_c::clientSimple xmc_client;
			string const methodName("get_task_status");
			xmlrpc_c::value result;
			xmlrpc_c::paramList params;

			//会议名
			params.add(xmlrpc_c::value_string(meet_->name));

			xmc_client.call(xd_api_->strXmlRpcServerAddr, methodName, params, &result);

			if (result.type() == xmlrpc_c::value::TYPE_INT)
			{
				int nRet = xmlrpc_c::value_int(result);

		
				return false;
			}
			else if (result.type() == xmlrpc_c::value::TYPE_STRUCT)
			{
				map<string, xmlrpc_c::value>  resultTaskStatusBrief = xmlrpc_c::value_struct(result);
				//会议名称
				string strConfName = xmlrpc_c::value_string(resultTaskStatusBrief["_name"]);
				//strcpy(ptConfStatus->acConfName, strConfName.c_str());
				//会议号
				//strcpy(ptConfStatus->acConfNumber, pContainerInfo->acNumber);
				//内部使用的数据库会议ID
				//ptConfStatus->unConfId = pContainerInfo->unConfId;
				//会议模式
				//ptConfStatus->nConfMode = xmlrpc_c::value_int(resultTaskStatusBrief["_mode"]);
				//会议最大终端数量
				//ptConfStatus->nMaxTerminals = xmlrpc_c::value_int(resultTaskStatusBrief["_max_terminals"]);

				//会议当前的终端列表
				xmlrpc_c::value_array  terminalsArray = resultTaskStatusBrief["_terminal_status"];
				vector<xmlrpc_c::value> const vTerminalStatusBrief(terminalsArray.vectorValueValue());

				int nSize = vTerminalStatusBrief.size();
				//ptConfStatus->unTerminalNum = (UINT)nSize;
				for (int i = 0; i < nSize; i++)
				{
					xmlrpc_c::value_struct sTerminalStatusBrief = xmlrpc_c::value_struct(vTerminalStatusBrief[i]);
					map<string, xmlrpc_c::value> TerminalStatusBriefMap(static_cast<map<string, xmlrpc_c::value>>(sTerminalStatusBrief));

					//终端是否开启双流
					//ptConfStatus->atTerminalsStatusArray[i].bEnableExt = xmlrpc_c::value_boolean(TerminalStatusBriefMap["_enable_ext"]);

					//终端的呼叫状态
					int nCallState = xmlrpc_c::value_int(TerminalStatusBriefMap["_state"]);

					//*************MC状态***********//
					map<string, xmlrpc_c::value>  callStatus = xmlrpc_c::value_struct(TerminalStatusBriefMap["_mc_status"]);
					//终端E164ID
					string strTerminalE164 = xmlrpc_c::value_string(callStatus["_e164"]);
					

					//终端名称
					string strTerminalName = xmlrpc_c::value_string(callStatus["_name"]);
					

					//终端是否在线
					bool bConnected = xmlrpc_c::value_boolean(callStatus["_connected"]);

					//**************MP状态***************//
					map<string, xmlrpc_c::value>  participantStatusBrief = xmlrpc_c::value_struct(TerminalStatusBriefMap["_mp_status"]);
					//终端角色
					int nRole = xmlrpc_c::value_int(participantStatusBrief["_role"]);
					//终端各路流的状态[主视频、辅视频、音频]
					xmlrpc_c::value_array  sessionsArray = participantStatusBrief["_sessions"];
					vector<xmlrpc_c::value> const vSessionsStatus(sessionsArray.vectorValueValue());
					int nSessionsNum = vSessionsStatus.size();
					bool bmute = true;
					for (int j = 0; j < nSessionsNum; j++)
					{
						xmlrpc_c::value_struct sSessionStatus = xmlrpc_c::value_struct(vSessionsStatus[j]);
						map<string, xmlrpc_c::value> SessionStatusMap(static_cast<map<string, xmlrpc_c::value>>(sSessionStatus));
						int nWhich = xmlrpc_c::value_int(SessionStatusMap["_which"]);
						if (nWhich == 0)
						{
							//音频
							/*ptConfStatus->atTerminalsStatusArray[i].tAudioStatus.nDirection = xmlrpc_c::value_int(SessionStatusMap["_direction"]);
							ptConfStatus->atTerminalsStatusArray[i].tAudioStatus.nInCodec = xmlrpc_c::value_int(SessionStatusMap["_in_codec"]);
							ptConfStatus->atTerminalsStatusArray[i].tAudioStatus.nInLostPackets = xmlrpc_c::value_int(SessionStatusMap["_in_packetloss"]);
							ptConfStatus->atTerminalsStatusArray[i].tAudioStatus.nInTotalPackets = xmlrpc_c::value_int(SessionStatusMap["_in_packettotal"]);

							ptConfStatus->atTerminalsStatusArray[i].tAudioStatus.nOutCodec = xmlrpc_c::value_int(SessionStatusMap["_out_codec"]);
							ptConfStatus->atTerminalsStatusArray[i].tAudioStatus.nOutLostPackets = xmlrpc_c::value_int(SessionStatusMap["_out_packetloss"]);
							ptConfStatus->atTerminalsStatusArray[i].tAudioStatus.nOutTotalPackets = xmlrpc_c::value_int(SessionStatusMap["_out_packettotal"]);*/

							//是否禁麦克
							bmute = xmlrpc_c::value_boolean(SessionStatusMap["_in_mute"]);
							//是否禁扬声器
							//ptConfStatus->atTerminalsStatusArray[i].bOutMute = xmlrpc_c::value_boolean(SessionStatusMap["_out_mute"]);
						}
						
						
						

					}


					terminal* ter = name_get_ter(strTerminalName);
					if (ter) {
						ter->audio_mute = bmute;
						ter->state = bConnected ? meet_state::connected : meet_state::remove;
						if (nRole == e_Speaker) {
							ter->roll = true;
						}
						else {
							ter->roll = false;
						}
						meet_room_->ws_ter_update(ter);
					}
					else {
						ter = new terminal();
						ter->obj_id = utils_string::generate_uuid();
						ter->invite_time = 0;
						ter->name = ter->real_name = strTerminalName;
						ter->is_tmp = true;
						ter->init_weight = ter->weight = ter->layout_weight = ter->sort_weight = meet_room_->last_weight_;

						meet_room_->last_weight_ -= 20;
						name_terminal_map_[ter->name] = ter;
						meet_room_->terminal_list_.push_back(ter);
						meet_room_->obj_terminal_map_[ter->obj_id] = ter;
						auto info_ret = xd_api_->get_participant_status(meet_->meet_name, strTerminalName);
						if (info_ret.first.ret) {
							json info = info_ret.second;
							if (info.contains("domain")) {
								ter->ip = ter->sip_uri = info["domain"];
							}
						}
						
						meet_room_->ter_added(ter);
					}

				}

				return true;
			}
			else
			{
				return false;
			}

		}
		catch (exception const& e)
		{
			
		}
		return false;
		
	}

	json xd_room::get_participant_status(terminal* ter)
	{
		auto info_ret =  xd_api_->get_participant_status(meet_->meet_name, ter->name);
		if (!info_ret.first.ret) {
			//meet_room_->error_msg(info_ret.first.err_code);
		}

		return info_ret.second;
	}

	void xd_room::on_msg(const string& meet_name, const string& ter_name, const string& action)
	{
		//WLOG << "on_msg meet_name=" << meet_name << " ter_name="<< ter_name<<" action="<< action;
		if (meet_name == meet_->meet_name) {

			if (ter_name.empty()) {
				//会议室消息
				if (action == "task stop") {
					meet_room_->end_meet().via(meet_room_).detach();
				}
			}
			else {
				//终端消息
				terminal* ter = name_get_ter(ter_name);
				if (ter) {
					//WLOG << "xd_room::on_msg meet_name =" << meet_name << ",ter_name=" << ter_name << ",action=" << action;
					if (action == "connecting") {
						ter->state = meet_state::initial;
					}
					else if (action == "disconnected")
					{
						ter->state = meet_state::remove;
					}
					else if (action == "hands down") {
						ter->state = meet_state::remove;
					}
					else if (action == "connected") {
						ter->state = meet_state::connected;
						if (ter->is_main) {
							xd_api_->toggle_audio_mute(meet_->meet_name, ter->name, 1, false);
						}
					}
					else if (action == "mic off") {
						ter->audio_mute = true;
					}
					else if (action == "mic on") {
						ter->audio_mute = false;
					}
					else if (action == "role speaker") {
						ter->roll = true;
						ter->choose = false;
					}
					else if (action == "role normal") {
						ter->roll = false;
					}
					else if (action == "kicked") {
						name_terminal_map_.erase(ter->name);


						json ter_obj;
						to_json(ter_obj, *ter);
						meet_room_->push_ws_msg(ws_msg_type::participant_remove, ter_obj);

						meet_room_->remove_ter(ter);
						return;
					}
					meet_room_->ws_ter_update(ter);
				}
				else 
				{
					if (action == "added" || action =="connected")
					{
						ter = new terminal();
						ter->obj_id = utils_string::generate_uuid();
						ter->invite_time = 0;
						ter->name = ter->real_name = ter_name;
						ter->is_tmp = true;
						ter->init_weight = ter->weight = ter->layout_weight = ter->sort_weight = meet_room_->last_weight_;
						
						meet_room_->last_weight_ -= 20;
						name_terminal_map_[ter->name] = ter;
						meet_room_->terminal_list_.push_back(ter);
						meet_room_->obj_terminal_map_[ter->obj_id] = ter;
						auto info_ret = xd_api_->get_participant_status(meet_->meet_name, ter_name);
						if (info_ret.first.ret) {
							json info = info_ret.second;
							if (info.contains("domain")) {
								ter->ip = ter->sip_uri = info["domain"];
							}
						}
						
						meet_room_->ter_added(ter);
					}
				}
				
			}
		}
		
	}


	terminal* xd_room::name_get_ter(const string& name)
	{
		auto it = name_terminal_map_.find(name);
		if (it != name_terminal_map_.end()) {
			return it->second;
		}
		return nullptr;
	}

	

	

	



	





	


	

	
	
	

	


	

	

	

	

	



	
	

	


	


	
}